/*
 * A simple CORBA banking application
 * Part of the GICOM pedagogical project
 */

package gicom.bank;

import gicom.PersistentObject;
import gicom.generated.bankServices.AccountOperations;
import gicom.generated.bankServices.AccountPOATie;
import gicom.generated.bankServices.ConcurrencyControlException;
import gicom.generated.bankServices.Customer;
import gicom.generated.bankServices.CustomerHelper;
import gicom.generated.bankServices.ProblemException;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.logging.Logger;
import org.omg.CORBA.ORB;
import org.omg.PortableServer.POA;
import org.omg.PortableServer.Servant;

/**
 * The transient Account implementation
 */

public class AccountImpl extends PersistentObject implements AccountOperations {
    /**
     * The account balance
     */
    private float balance = 0;

    /**
     * The account number
     */
    private String accountId = null;

    /**
     * The account number
     */
    private transient Customer customer;

    /**
     * readStamp of the account
     */
    private int readStamp;

    /**
     * writeStamp of the account
     */
    private int writeStamp;

    /**
     * Create an account
     * 
     * @param accountId
     *                the account number
     * @param customer
     *                the customer's reference
     * @param initBalance
     *                the account initial balance
     */
    public AccountImpl(String number, float initBalance, Customer customer) {
        super(number);
        this.balance = initBalance;
        this.accountId = number;
        this.customer = customer;
    }

    public AccountImpl() {

    }

    /**
     * @return the account number
     */
    public String number() {
	return this.accountId;
    }

    /**
     * @return the account balance
     */
    public float balance() {
        return this.balance;
    }

    /**
     * Debit the account
     * 
     * @param amount
     *                the debit amount
     * @throws ProblemException
     *                 This exception is raised when a problem occurs in the
     *                 banking business methods
     */
    public void debit(float amount) throws ProblemException {
	if (amount < 0)
	    throw new ProblemException("Account error", "This account is empty");
	if (amount > balance)
	    throw new ProblemException("Account error", "You have not enough balance in this account!");
	balance -= amount;
	// this.save();
    }

    /**
     * Credit the account
     * 
     * @param amount
     *                the credit amount
     * @throws ProblemException
     *                 This exception is raised when a problem occurs in the
     *                 banking business methods
     */
    public void credit(float amount) throws ProblemException {
	if (amount < 0)
	    throw new ProblemException("Account error", "This account is empty");
	balance += amount;
	// this.save();
    }

    public Customer refCustomer() {
	return customer;
    }

    public Servant createServant() {
	return new AccountPOATie(this);
    }

    /*
     * Persistence
     * 
     */

    private transient String refCustomer;

    @Override
    public void doReload(ORB orb, POA poa) throws Exception {
        Logger.getLogger(this.getClass().getName()).info("Reinitialisation de l'Account numero : " + this.accountId);
        customer = CustomerHelper.narrow(orb.string_to_object(refCustomer));
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {

	// balance
	this.balance = in.readFloat();

	// acoundId
	this.accountId = in.readUTF();

	// customer
	refCustomer = in.readUTF();

    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        try {

            // balance
            out.writeFloat(this.balance);

            // accountId
            out.writeUTF(this.accountId);

            // customer
            out.writeUTF(getORB().object_to_string(customer));
        } catch (Exception ex) {
            throw new IOException("Error while writing the object.", ex);
        }
    }

    /*
     * Stamps' getters and setters to ensure atomic actions
     */

    @Override
    public int readStamp() {
	return this.readStamp;
    }

    @Override
    public void readStamp(int newReadStamp) {
	this.readStamp = newReadStamp;
    }

    @Override
    public int writeStamp() {
	return this.writeStamp;
    }

    @Override
    public void writeStamp(int newWriteStamp) {
	this.writeStamp = newWriteStamp;
    }

    @Override
    public void free() throws ConcurrencyControlException {
	// TODO Auto-generated method stub
	
    }

    @Override
    public void prepare() throws ConcurrencyControlException {
	// TODO Auto-generated method stub
	
    }

    @Override
    public void saveTmp(String location) {
        // TODO : pom save transaction file
	//PersistentObjectManager per = PersistentObjectManagerImpl.getManager();
	
        //per.store(this, location.getBytes());
    }

}
